探索Promise用法和机制

您所在的位置:网站首页 reject todo 探索Promise用法和机制

探索Promise用法和机制

#探索Promise用法和机制 | 来源: 网络整理| 查看: 265

以前就会经常用到 Promise,但是没有去探究内部的实现机制。 正好由这次在小程序中引入了 Promise ,探究下内部原理。

为什么使用 Promise

Promise 可以让我们避免回调的地狱。以前我们可能使用的是 bluebird 或者 Q,现在我们已经有了原生的实现。1234567891011func1(function (value1) { func2(value1, function (value2) { func3(value2, function (value3) { func4(value3, function (value4) { func5(value4, function (value5) { // Do something with value 5 }); }); }); });});

使用 Promise 后,可以把平行的代码变成竖状的易读的代码。12345func1(value) .then(func2) .then(func3) .then(func4) .then(func5)

一个最常见的 Promise 的例子如下:1234567891011var request = require('request');return new Promise((resolve, reject) => { request.get(url, (error, response, body) => { if(body) { resolve(JSON.parse(body)); } else { resolve({}); //reject(....); } })})

小程序 Promise 化实现

小程序里,包括官方文档的 demo 里会看到很多的 cb, 比如我们获取用户身份信息就需要下面的操作:12345678910wx.login({ success: function () { wx.getUserInfo({ success: function (res) { that.globalData.userInfo = res.userInfo; typeof cb == "function" && cb(that.globalData.userInfo) } }) }});

这样略微深的嵌套一定程度的阻碍了我们的阅读和理解,代码整体也不好查 bug 和 扩展。所以我考虑到用 Promise 扩展一层。

但是由于小程序已经去除了 自带的 Promise ,所以需要开发者自动引入 Promise 库,或者编写相应的 Promise 库。这里我引入 es6-promise 这个库。注意不要使用 bluebird ,bluebird 会导致android 上有报错,因为这个里面有用到一些小程序不支持的比如 document, window之类的对象。

选取一小段没使用的代码如下:12345678910var Promise = require('es6-promise').Promise; var wxLib = require('../wxLib);wxLib.login().then(()=>{ wxLib.getUserInfo();}).catch(()=>{ wxLib.showErrorMsg();})

promise 更易我们看清整个的结构。更好的控制异步流程, 也可以让我们使用本来不方便使用的 return, throw 等。

更多其他的用法关于 Promise 的几个注意的地方 Promise 对象是一个构造函数,所以才需要 new Promise 生成一个 Pormise 的实例对象。 Promise 构造函数接受了两个参数,分别是 resolve 和 reject, 这两个函数由 js 引擎提供,不需要自己实现。 resolve 是将 Promise 对象从 未完成 => 成功。(pending => resolved), reject 是 将对象的状态从 未完成=> 失败。(pending=>rejected) then 方法接收两个回调函数。第一个是 Promise 返回 resolved 的时候调用的, 第二个是 返回 rejected 的时候调用的。 Promise catch 是 .then(null, rejection)的别名,里面的回调用于发生错误时使用。 12345678910111213141516// 这种情况不会捕捉then 里的错误promise .then(function(data) { // success }, function(err) { // error });// betterpromise .then(function(data) { //cb // success }) .catch(function(err) { // error }); 关于Promise.all的用法

var p = Promise.all([p1, p2, p3]);其中 Promise.all 会接收一个数组作为参数, p1,p2,p3都是 Promise 对象的实例。 如果不是,则调用 Promise.resolve 方法,将参数转化为 Promise 实例。

他们三个之间的关系是: 必须都变成 fulfilled , p才是 fulfilled, 只要有一个是 rejected, 就会是 rejected, 并且这个第一个被 reject 的实例的返回值就会给到 P。 haha, 挺团结的。

12345678910111213141516171819202122let urls = [ '/api/commits', '/api/issues/opened', '/api/issues/assigned', '/api/issues/completed', '/api/issues/comments', '/api/pullrequests'];let promises = urls.map((url) => { return new Promise((resolve, reject) => { $.ajax({ url: url }) .done((data) => { resolve(data); }) })})Promise.all(promises) .then((results) => { // results is an array list})

有一个方法叫做 Promise.race() 跟 Promise.all 差不多。也是

var p = Promise.race([p1, p2, p3]);

p1, p2, p3 只要有一个率先改变,p 的状态就会改,并且把这个率先改的返回值给到 P。

Promise.resolve() 的 用法

上面提到了, promise.all 和 promise.race 的参数 p1, p2, p3 都必须是 promise 的实例对象。 如果不是,就需要转化为 Promise 对象。 Promise.resolve 就派上了用法。

12Promise.resolve('foo');new Promise(resolve => resolve('foo'));

Promise.resolve 方法的参数分成下面几个情况:

Promise.resolve(value);

Promise.resolve(promise);

Promise.resolve(thenable);

12345678910Promise.resolve("Success").then(function(value) { console.log(value); // "Success"}, function(value) { // 不会被调用});var p = Promise.resolve([1,2,3]);p.then(function(v) { console.log(v[0]); // 1}); 实现一个简易的 Promise

这里实现的过程我参考阅读了很多篇文章,感谢,具体有:

剖析Promise内部结构 how-do-promises-work JS Promise的实现原理

先搭一个简单的框架。

构造函数的实现123456789101112131415161718192021// processor 就是传给 Promise 的函数function Promise(processor) { this.status = 'pending'; this.data = undefined; this.onResolvedCb = []; this.onRejectedCb = []; this.resolve = (value) => { //TODO } this.reject = (reason) => { //TODO } try{ (typeof processor === 'function') && processor(resolve, reject); }catch(e) { reject(e); } }

然后是对 resolve 和 reject 的实现, 我们用原生的 Promise 的时候不需要实现这两个函数,是因为 JS 引擎已经帮我们做了这件事情。

123456789101112131415161718this.resolve = (value) => { if(this.status === 'resolved' || this.status === 'pending') { this.status = 'resolved'; this.data = value; for(var i = 0, l = this.onResolvedCb.length; i < l; i++) { //执行回调函数 this.onResolvedCb[i].value; } }}// reject 就和 resolve 非常像this.reject = (reson) => { if(this.status === 'rejected' || this.status === 'pending'){ this.status = 'rejected'; //...... }} then 函数的实现1234567891011121314151617181920212223242526272829Promise.prototype.then = (onResolved, onRejected) => { onResolved = typeof onResolved === 'function' ? onResolved : function(value) {} onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {} if(this.status === 'resolved'){ return new Promise((resolve, reject) => { try{ let x = onResolved(self.data); if(x instanceof Promise) { x.then(resolve, reject); } resolve(x); } catch (e) { reject(e); } }) }else if(this.status === 'rejected') { return new Promise((resolve, reject) => { //TODO }) }else{ //pending return new Promise((resolve, reject) => { //TODO }) }} 总结

上面只是一个粗浅的大概。如果要丰富 Promise , 还要去实现很多其他的内容,比如 catch 之类的。关于异步还有很多要学习,其实大部分都学习过,只是因为使用的少,没有考虑他内部的实现,也比较容易忘记。还是实践是王道。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3